Coverage Report

Created: 2024-12-26 12:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
D:\a\tools.proto\tools.proto\compiler\src\compiler\message.rs
Line
Count
Source
1
// Copyright (c) 2024, BlockProject 3D
2
//
3
// All rights reserved.
4
//
5
// Redistribution and use in source and binary forms, with or without modification,
6
// are permitted provided that the following conditions are met:
7
//
8
//     * Redistributions of source code must retain the above copyright notice,
9
//       this list of conditions and the following disclaimer.
10
//     * Redistributions in binary form must reproduce the above copyright notice,
11
//       this list of conditions and the following disclaimer in the documentation
12
//       and/or other materials provided with the distribution.
13
//     * Neither the name of BlockProject 3D nor the names of its contributors
14
//       may be used to endorse or promote products derived from this software
15
//       without specific prior written permission.
16
//
17
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29
use crate::compiler::builder::FieldBuilder;
30
use crate::compiler::error::Error;
31
use crate::compiler::structure::{FixedFieldType, Structure};
32
use crate::compiler::union::Union;
33
use crate::compiler::util::objects::name_index;
34
use crate::compiler::util::types::{Name, PtrKey};
35
use crate::compiler::Protocol;
36
use crate::model::message::MessageFieldValue;
37
use crate::model::protocol::{Description, Endianness};
38
use crate::model::structure::StructFieldRaw;
39
use bp3d_debug::{error, trace};
40
use std::cell::Cell;
41
use std::fmt::{Display, Formatter};
42
use std::rc::Rc;
43
44
#[derive(Clone, Debug)]
45
pub enum Referenced {
46
    Struct(Rc<Structure>),
47
    Message(Rc<Message>),
48
}
49
50
impl Name for Referenced {
51
37
    fn name(&self) -> &str {
52
37
        match self {
53
27
            Referenced::Struct(v) => &v.name,
54
10
            Referenced::Message(v) => &v.name,
55
        }
56
37
    }
57
}
58
59
impl PtrKey for Referenced {
60
63
    fn ptr_key(&self) -> usize {
61
63
        match self {
62
54
            Referenced::Struct(v) => v.ptr_key(),
63
9
            Referenced::Message(v) => v.ptr_key(),
64
        }
65
63
    }
66
}
67
68
impl Referenced {
69
64
    pub fn lookup(proto: &Protocol, reference_name: &str) -> Option<Self> {
70
64
        proto
71
64
            .structs
72
64
            .get(reference_name)
73
64
            .map(|v| 
Referenced::Struct(v.clone())41
)
74
64
            .or_else(|| 
proto.messages.get(reference_name).map(23
|v|
Referenced::Message(v.clone())23
)23
)
75
64
    }
76
}
77
78
#[derive(Clone, Debug)]
79
pub struct FixedContainerField {
80
    pub ty: FixedFieldType,
81
    pub item_type: Rc<Structure>,
82
}
83
84
impl Display for FixedContainerField {
85
10
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
86
10
        write!(f, "FixedContainer<{}, Len = {}>", self.item_type.name, self.ty)
87
10
    }
88
}
89
90
#[derive(Clone, Debug)]
91
pub struct SizedBufferField {
92
    pub ty: FixedFieldType,
93
}
94
95
impl Display for SizedBufferField {
96
14
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
97
14
        write!(f, "Varbuf<{}>", self.ty)
98
14
    }
99
}
100
101
#[derive(Clone, Debug)]
102
pub struct ContainerField {
103
    pub ty: FixedFieldType,
104
    pub item_type: Rc<Message>,
105
    pub nested: bool,
106
}
107
108
impl Display for ContainerField {
109
25
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
110
25
        write!(f, "Container<{}, Len = {}>", self.item_type.name(), self.ty)
111
25
    }
112
}
113
114
#[derive(Clone, Debug)]
115
pub struct SizedContainerField {
116
    pub ty: FixedFieldType,
117
    pub item_type: Rc<Message>,
118
    pub size_ty: FixedFieldType,
119
}
120
121
impl Display for SizedContainerField {
122
9
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
123
9
        write!(
124
9
            f,
125
9
            "SizedContainer<{}, Len = {}, Size = {}>",
126
9
            self.item_type.name(),
127
9
            self.ty,
128
9
            self.size_ty
129
9
        )
130
9
    }
131
}
132
133
#[derive(Clone, Debug)]
134
pub struct FixedField {
135
    pub ty: FixedFieldType,
136
}
137
138
impl Display for FixedField {
139
8
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
140
8
        write!(f, "{}", self.ty)
141
8
    }
142
}
143
144
#[derive(Clone, Debug)]
145
pub struct UnionField {
146
    pub r: Rc<Union>,
147
}
148
149
impl Display for UnionField {
150
8
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
151
8
        f.write_str(self.r.name())
152
8
    }
153
}
154
155
#[derive(Clone, Debug)]
156
pub enum FieldType {
157
    Fixed(FixedField),
158
    Ref(Referenced),
159
160
    /// A buffer field is a field which has a known size which can be determined at runtime
161
    /// (ex: a null-terminated string).
162
    Buffer,
163
164
    /// A sized buffer field is a field which has a known size field based on a configurable type
165
    /// (ex: a Varchar).
166
    SizedBuffer(SizedBufferField),
167
168
    /// A fixed container is a container which can store only fixed size elements (structures).
169
    FixedContainer(FixedContainerField),
170
171
    Union(UnionField),
172
173
    /// A container can store dynamically sized elements.
174
    Container(ContainerField),
175
176
    /// A container which has an additional configurable size field to detect the size in bytes of
177
    /// the container.
178
    SizedContainer(SizedContainerField),
179
180
    Payload,
181
}
182
183
impl Display for FieldType {
184
125
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
185
125
        match self {
186
8
            FieldType::Fixed(v) => v.fmt(f),
187
29
            FieldType::Ref(v) => f.write_str(v.name()),
188
22
            FieldType::Buffer => f.write_str("Buffer"),
189
14
            FieldType::SizedBuffer(v) => v.fmt(f),
190
10
            FieldType::FixedContainer(v) => v.fmt(f),
191
8
            FieldType::Union(v) => v.fmt(f),
192
25
            FieldType::Container(v) => v.fmt(f),
193
9
            FieldType::SizedContainer(v) => v.fmt(f),
194
0
            FieldType::Payload => f.write_str("Bytes"),
195
        }
196
125
    }
197
}
198
199
impl FieldType {
200
55
    pub fn is_message_reference(&self) -> bool {
201
55
        match self {
202
14
            FieldType::Ref(v) => match v {
203
10
                Referenced::Struct(_) => false,
204
4
                Referenced::Message(_) => true,
205
            },
206
41
            _ => false,
207
        }
208
55
    }
209
210
30
    pub fn is_union(&self) -> bool {
211
30
        
matches!16
(self, FieldType::Union(_))
212
30
    }
213
214
69
    pub fn is_string(&self) -> bool {
215
69
        
matches!44
(self, FieldType::SizedBuffer(_) | FieldType::Buffer)
216
69
    }
217
}
218
219
#[derive(Copy, Clone, Debug)]
220
pub struct SizeInfo {
221
    pub is_dyn_sized: bool,
222
    pub is_element_dyn_sized: bool,
223
}
224
225
#[derive(Clone, Debug)]
226
pub struct HeaderField {
227
    pub name: String,
228
    pub index: usize,
229
}
230
231
impl HeaderField {
232
76
    fn from_model(header: Option<String>, fields: &[Field]) -> Result<(Option<Self>, Option<&Field>), Error> {
233
76
        match header {
234
12
            Some(header) => {
235
12
                let (
index, field11
) = fields
236
12
                    .iter()
237
12
                    .enumerate()
238
12
                    .find_map(|(k, v)| 
if v.name == header11
{
Some((k, v))11
} else {
None0
}11
)
  Branch (238:43): [True: 11, False: 0]
  Branch (238:43): [Folded - Ignored]
239
12
                    .ok_or(Error::UndefinedReference(header))
?1
;
240
11
                let header = HeaderField {
241
11
                    index,
242
11
                    name: field.name.clone(),
243
11
                };
244
11
                Ok((Some(header), Some(field)))
245
            }
246
64
            None => Ok((None, None)),
247
        }
248
76
    }
249
}
250
251
#[derive(Clone, Debug)]
252
pub struct Field {
253
    pub name: String,
254
    pub header: Option<HeaderField>,
255
    pub ty: FieldType,
256
    pub optional: bool,
257
    pub size: SizeInfo,
258
    pub endianness: Endianness,
259
    pub description: Option<Description>,
260
    pub codec: Option<String>,
261
}
262
263
impl Display for Field {
264
125
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
265
125
        match (self.optional, &self.codec) {
266
6
            (true, None) => write!(f, "{}: {}?, {} endian", self.name, self.ty, self.endianness),
267
39
            (false, None) => write!(f, "{}: {}, {} endian", self.name, self.ty, self.endianness),
268
15
            (true, Some(v)) => write!(f, "{}: {} ({})?, {} endian", self.name, v, self.ty, self.endianness),
269
65
            (false, Some(v)) => write!(f, "{}: {} ({}), {} endian", self.name, v, self.ty, self.endianness),
270
        }
271
125
    }
272
}
273
274
impl Field {
275
279
    pub fn codec(&self) -> &str {
276
279
        self.codec.as_deref().unwrap_or("base")
277
279
    }
278
279
78
    fn from_model(
280
78
        proto: &Protocol,
281
78
        unsorted: &[Field],
282
78
        has_headers: bool,
283
78
        value: crate::model::message::MessageField,
284
78
    ) -> Result<Self, Error> {
285
78
        if (value.value.is_none() && 
value.item_type.is_none()20
) || (
value.value.is_some()77
&&
value.item_type.is_some()58
)
  Branch (285:13): [True: 20, False: 58]
  Branch (285:38): [True: 1, False: 19]
  Branch (285:69): [True: 58, False: 19]
  Branch (285:94): [True: 1, False: 57]
  Branch (285:13): [Folded - Ignored]
  Branch (285:38): [Folded - Ignored]
  Branch (285:69): [Folded - Ignored]
  Branch (285:94): [Folded - Ignored]
286
        {
287
2
            return Err(Error::BadFieldType);
288
76
        }
289
76
        let (
header, header_field75
) = HeaderField::from_model(value.header, unsorted)
?1
;
290
75
        if let Some(
field11
) = header_field {
  Branch (290:16): [True: 11, False: 64]
  Branch (290:16): [Folded - Ignored]
291
10
            match &field.ty {
292
10
                FieldType::Ref(Referenced::Struct(v)) => v.set_used_in_header(),
293
1
                v => {
294
1
                    error!(
295
1
                        "Invalid header field type, expected struct reference, got field type {:?}",
296
1
                        v
297
1
                    );
298
1
                    return Err(Error::InvalidHeaderType);
299
                }
300
            }
301
64
        }
302
74
        let builder = FieldBuilder::new(value.name, value.optional.unwrap_or_default(), proto.endianness)
303
74
            .description(value.description)
304
74
            .header(header)
305
74
            .codec(value.codec);
306
74
        if let Some(
info55
) = value.value {
  Branch (306:16): [True: 55, False: 19]
  Branch (306:16): [Folded - Ignored]
307
55
            match info {
308
                MessageFieldValue::List {
309
16
                    max_len,
310
16
                    item_type,
311
16
                    max_size,
312
16
                    nested,
313
16
                } => {
314
16
                    if max_len == 0 {
  Branch (314:24): [True: 1, False: 15]
  Branch (314:24): [Folded - Ignored]
315
1
                        return Err(Error::ZeroArray);
316
15
                    }
317
15
                    if builder.has_codec() {
  Branch (317:24): [True: 0, False: 15]
  Branch (317:24): [Folded - Ignored]
318
0
                        return Err(Error::ForbiddenCodec(builder.name().into()));
319
15
                    }
320
15
                    let r = Referenced::lookup(proto, &item_type).ok_or(Error::UndefinedReference(item_type))
?0
;
321
15
                    let ty = FixedFieldType::from_max_value(max_len)
?0
;
322
15
                    match r {
323
4
                        Referenced::Struct(item_type) => Ok(builder
324
4
                            .codec(Some("list".into()))
325
4
                            .build(FieldType::FixedContainer(FixedContainerField { item_type, ty }))),
326
11
                        Referenced::Message(item_type) => {
327
11
                            if let Some(
max_size3
) = max_size {
  Branch (327:36): [True: 3, False: 8]
  Branch (327:36): [Folded - Ignored]
328
3
                                if max_size == 0 {
  Branch (328:36): [True: 1, False: 2]
  Branch (328:36): [Folded - Ignored]
329
1
                                    return Err(Error::ZeroArray);
330
2
                                }
331
2
                                let size_ty = FixedFieldType::from_max_value(max_size)
?0
;
332
2
                                Ok(builder
333
2
                                    .codec(Some("list".into()))
334
2
                                    .size_info(SizeInfo {
335
2
                                        is_element_dyn_sized: false,
336
2
                                        is_dyn_sized: true,
337
2
                                    })
338
2
                                    .build(FieldType::SizedContainer(SizedContainerField {
339
2
                                        ty,
340
2
                                        item_type,
341
2
                                        size_ty,
342
2
                                    })))
343
                            } else {
344
8
                                item_type.embedded.set(true);
345
8
                                Ok(
346
8
                                    builder.codec(Some("list".into())).dynamic_size().build(FieldType::Container(
347
8
                                        ContainerField {
348
8
                                            ty,
349
8
                                            item_type,
350
8
                                            nested: nested.unwrap_or_default(),
351
8
                                        },
352
8
                                    )),
353
8
                                )
354
                            }
355
                        }
356
                    }
357
                }
358
                MessageFieldValue::Container {
359
4
                    max_len,
360
4
                    item_type,
361
4
                    max_size,
362
4
                    nested,
363
4
                } => {
364
4
                    if max_len == 0 {
  Branch (364:24): [True: 0, False: 4]
  Branch (364:24): [Folded - Ignored]
365
0
                        return Err(Error::ZeroArray);
366
4
                    }
367
4
                    let r = Referenced::lookup(proto, &item_type).ok_or(Error::UndefinedReference(item_type))
?0
;
368
4
                    let ty = FixedFieldType::from_max_value(max_len)
?0
;
369
4
                    match r {
370
0
                        Referenced::Struct(item_type) => {
371
0
                            Ok(builder.build(FieldType::FixedContainer(FixedContainerField { item_type, ty })))
372
                        }
373
4
                        Referenced::Message(item_type) => {
374
4
                            if let Some(
max_size2
) = max_size {
  Branch (374:36): [True: 2, False: 2]
  Branch (374:36): [Folded - Ignored]
375
2
                                if max_size == 0 {
  Branch (375:36): [True: 0, False: 2]
  Branch (375:36): [Folded - Ignored]
376
0
                                    return Err(Error::ZeroArray);
377
2
                                }
378
2
                                let size_ty = FixedFieldType::from_max_value(max_size)
?0
;
379
2
                                Ok(builder
380
2
                                    .size_info(SizeInfo {
381
2
                                        is_element_dyn_sized: false,
382
2
                                        is_dyn_sized: true,
383
2
                                    })
384
2
                                    .build(FieldType::SizedContainer(SizedContainerField {
385
2
                                        ty,
386
2
                                        item_type,
387
2
                                        size_ty,
388
2
                                    })))
389
                            } else {
390
2
                                item_type.embedded.set(true);
391
2
                                Ok(builder.dynamic_size().build(FieldType::Container(ContainerField {
392
2
                                    ty,
393
2
                                    item_type,
394
2
                                    nested: nested.unwrap_or_default(),
395
2
                                })))
396
                            }
397
                        }
398
                    }
399
                }
400
19
                MessageFieldValue::String { max_len } => {
401
19
                    if builder.has_codec() {
  Branch (401:24): [True: 0, False: 19]
  Branch (401:24): [Folded - Ignored]
402
0
                        return Err(Error::ForbiddenCodec(builder.name().into()));
403
19
                    }
404
19
                    match max_len {
405
13
                        None => Ok(builder.codec(Some("string".into())).build(FieldType::Buffer)),
406
6
                        Some(max_len) => {
407
6
                            if max_len == 0 {
  Branch (407:32): [True: 1, False: 5]
  Branch (407:32): [Folded - Ignored]
408
1
                                return Err(Error::ZeroArray);
409
5
                            }
410
5
                            let ty = FixedFieldType::from_max_value(max_len)
?0
;
411
5
                            Ok(builder
412
5
                                .codec(Some("string".into()))
413
5
                                .build(FieldType::SizedBuffer(SizedBufferField { ty })))
414
                        }
415
                    }
416
                }
417
4
                MessageFieldValue::Buffer { max_len } => match max_len {
418
0
                    None => Ok(builder.build(FieldType::Buffer)),
419
4
                    Some(max_len) => {
420
4
                        if max_len == 0 {
  Branch (420:28): [True: 0, False: 4]
  Branch (420:28): [Folded - Ignored]
421
0
                            return Err(Error::ZeroArray);
422
4
                        }
423
4
                        let ty = FixedFieldType::from_max_value(max_len)
?0
;
424
4
                        Ok(builder.build(FieldType::SizedBuffer(SizedBufferField { ty })))
425
                    }
426
                },
427
7
                MessageFieldValue::Union { name } => {
428
7
                    let 
r6
= proto.unions.get(&name).ok_or(Error::UndefinedReference(name))
?1
;
429
6
                    let 
header_field5
= header_field.ok_or(Error::MissingHeaderForUnion)
?1
;
430
5
                    match &header_field.ty {
431
5
                        FieldType::Ref(Referenced::Struct(v)) => {
432
5
                            if !Rc::ptr_eq(&r.discriminant.root, v) {
  Branch (432:32): [True: 1, False: 4]
  Branch (432:32): [Folded - Ignored]
433
1
                                error!(
434
1
                                    "Union discriminant type mismatch, expected {}, got {}",
435
1
                                    v.name, r.discriminant.root.name
436
1
                                );
437
1
                                return Err(Error::UnionTypeMismatch);
438
4
                            }
439
                        }
440
0
                        _ => unreachable!(),
441
                    }
442
4
                    if value.optional.unwrap_or_default() {
  Branch (442:24): [True: 0, False: 4]
  Branch (442:24): [Folded - Ignored]
443
0
                        eprintln!("WARNING: ignoring unsupported optional flag on union message field!");
444
4
                    }
445
4
                    Ok(builder.size_info(r.size).build(FieldType::Union(UnionField { r: r.clone() })))
446
                }
447
0
                MessageFieldValue::Payload => Ok(builder.dynamic_size().build(FieldType::Payload)),
448
5
                MessageFieldValue::Unsigned { bits } => {
449
5
                    let ty = FixedFieldType::from_model(StructFieldRaw::Unsigned { bits })
?0
;
450
5
                    Ok(builder.fixed_size().build(FieldType::Fixed(FixedField { ty })))
451
                }
452
            }
453
        } else {
454
19
            let item_type = unsafe { value.item_type.unwrap_unchecked() };
455
19
            let r = Referenced::lookup(proto, &item_type).ok_or(Error::UndefinedReference(item_type))
?0
;
456
19
            match r {
457
15
                Referenced::Struct(r) => {
458
15
                    let is_single = r.fields.len() == 1;
459
15
                    let is_fixed = r.fields[0].ty.as_fixed().is_some();
460
15
                    let is_none = r.fields[0].ty.as_fixed().map(|v| v.raw.is_none()).unwrap_or_default();
461
15
                    let is_byte_aligned = r.fields[0].loc.bit_size % 8 == 0;
462
15
                    trace!({has_headers} {is_single} {is_fixed} {is_none} {is_byte_aligned}, "Found struct reference: {}", r.name);
463
15
                    if !has_headers && 
is_single7
&&
is_fixed3
&&
is_none3
&&
is_byte_aligned3
{
  Branch (463:24): [True: 7, False: 8]
  Branch (463:40): [True: 3, False: 4]
  Branch (463:53): [True: 3, False: 0]
  Branch (463:65): [True: 3, False: 0]
  Branch (463:76): [True: 3, False: 0]
  Branch (463:24): [Folded - Ignored]
  Branch (463:40): [Folded - Ignored]
  Branch (463:53): [Folded - Ignored]
  Branch (463:65): [Folded - Ignored]
  Branch (463:76): [Folded - Ignored]
464
3
                        let fixed = unsafe { r.fields[0].ty.as_fixed().unwrap_unchecked() };
465
3
                        Ok(builder.fixed_size().build(FieldType::Fixed(FixedField { ty: fixed.bits_type })))
466
                    } else {
467
12
                        Ok(builder.fixed_size().build(FieldType::Ref(Referenced::Struct(r))))
468
                    }
469
                }
470
4
                Referenced::Message(r) => Ok(builder.size_info(r.size).build(FieldType::Ref(Referenced::Message(r)))),
471
            }
472
        }
473
78
    }
474
}
475
476
#[derive(Clone, Debug)]
477
pub struct Message {
478
    pub name: String,
479
    pub description: Option<Description>,
480
    pub fields: Vec<Field>,
481
    pub size: SizeInfo,
482
    embedded: Cell<bool>,
483
}
484
485
impl Message {
486
33
    pub(crate) fn is_embedded(&self) -> bool {
487
33
        self.embedded.get()
488
33
    }
489
490
44
    pub fn from_model(proto: &Protocol, value: crate::model::message::Message) -> Result<Message, Error> {
491
44
        let mut fields = Vec::with_capacity(value.fields.len());
492
44
        let mut dyn_sized_elem_count = 0;
493
44
        let mut is_dyn_sized = false;
494
76
        let has_headers = value.fields.iter().any(|v| v.header.is_some()
)44
;
495
112
        for 
v78
in value.fields {
496
78
            let 
field68
= Field::from_model(proto, &fields, has_headers, v)
?10
;
497
68
            if field.size.is_dyn_sized {
  Branch (497:16): [True: 48, False: 20]
  Branch (497:16): [Folded - Ignored]
498
48
                is_dyn_sized = true;
499
48
            
}20
500
68
            if dyn_sized_elem_count > 0 && (
field.size.is_dyn_sized0
||
field.size.is_element_dyn_sized0
) {
  Branch (500:16): [True: 0, False: 68]
  Branch (500:45): [True: 0, False: 0]
  Branch (500:72): [True: 0, False: 0]
  Branch (500:16): [Folded - Ignored]
  Branch (500:45): [Folded - Ignored]
  Branch (500:72): [Folded - Ignored]
501
0
                return Err(Error::VarsizeAfterPayload);
502
68
            }
503
68
            if field.size.is_element_dyn_sized {
  Branch (503:16): [True: 10, False: 58]
  Branch (503:16): [Folded - Ignored]
504
10
                dyn_sized_elem_count += 1;
505
58
            }
506
68
            if dyn_sized_elem_count > 1 {
  Branch (506:16): [True: 0, False: 68]
  Branch (506:16): [Folded - Ignored]
507
0
                return Err(Error::MultiPayload);
508
68
            }
509
68
            fields.push(field);
510
        }
511
34
        Ok(Message {
512
34
            name: value.name,
513
34
            description: value.description,
514
34
            fields,
515
34
            size: SizeInfo {
516
34
                is_dyn_sized,
517
34
                is_element_dyn_sized: dyn_sized_elem_count > 0,
518
34
            },
519
34
            embedded: Cell::new(false),
520
34
        })
521
44
    }
522
}
523
524
name_index!(Message => name);